package advanced.jvm;

import org.apache.commons.io.IOUtils;

import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;

public class L_ClassLoader {
    public static void main(String[] args) throws ClassNotFoundException {
        System.out.println(ClassLoader.getPlatformClassLoader());
        System.out.println(ClassLoader.getSystemClassLoader().getParent());
        System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());


        System.out.println(System.getProperty("java.class.path"));

        System.out.println("_---------------------------");
        String a = "yeung";
        System.out.println(a.getClass().getClassLoader());
        System.out.println(a);
//        使用自定义的类加载器
        MyClassLoader myClassLoader = new MyClassLoader("");
        Class<?> cls = myClassLoader.loadClass("advanced.jvm.L_ClassLoader");
        System.out.println(cls);
    }
}

/**
 * 自定义文件系统类加载器
 */
class MyClassLoader extends ClassLoader {
    /*需求:
    传一个类的名字,
    在指定位置找到该类文件,并加载到内存中*/

    private String rootDir;

    MyClassLoader(String rootDir) {
        this.rootDir = rootDir;

    }

    @Override
    protected Class<?> findClass(String name) throws ClassNotFoundException {
        Class<?> loadedClass = findLoadedClass(name);//调用父类的方法, 继承来的
        if (loadedClass != null) return loadedClass;
//        应该要先查询是否已经加载了这个类, 没有的话在使用双亲委托机制去加载
        else {
            ClassLoader parent = this.getParent();
            try {
                loadedClass = parent.loadClass(name);
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                if (loadedClass != null) return loadedClass;
                else {
                    byte[] classData = getclassData(name);
                    if (classData == null) throw new ClassNotFoundException();
                    else {
                        loadedClass = defineClass(name, classData, 0, classData.length);
                    }
                }
            }

        }
        return loadedClass;
    }

    /**
     * 根据指定的类名到指定的路径去找到文件, 加载成字节数组返回结果
     *
     * @param name
     * @return
     */
    private byte[] getclassData(String name) {
        //找到这个文件, 加载进来,
        String path = rootDir + "/" + name.replace('.', '/') + ".class";
//        IOUtils 可以使用它将六种的数据转换成字节数组
        byte[] classData = null;
        try {
            classData = IOUtils.toByteArray(new FileReader(path), Charset.forName("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return classData;
    }
}
